#light

///Imports the shoemake methods from the CGraph.Shoemake dll.
module CGraph.Math.Shoemake

open System.Runtime.InteropServices

[<DllImport(@"CGraph.Shoemake.dll", EntryPoint="decomp_affine")>]
extern void decomp_affine(single* A, single* parts);


[<DllImport(@"CGraph.Shoemake.dll", EntryPoint="Qt_FromMatrixNoReturn")>]
extern void Qt_FromMatrix(single* A, single* quat); 

(*
HVect t;	/* Translation components */
    Quat  q;	/* Essential rotation	  */
    Quat  u;	/* Stretch rotation	  */
    HVect k;	/* Stretch factors	  */
    float f;	/* Sign of determinant	  */
    *)


type AffineParts = { 
    Translation:single array; 
    Rotation:single array; 
    StretchRotation:single array; 
    StretchFactors:single array; 
    DeterminantSign:single }

type HMatrix = single array
    
///Transfer an hmatrix to native format.
let HMatrixToNative (matrix:HMatrix) =
    let mutable freeFunc = []
    (*
    let decompVal0 = NativeInterop.PinnedArray.of_array(matrix.[0])
    freeFunc <- List.Cons( decompVal0.Free, freeFunc )
    let decompVal1 = NativeInterop.PinnedArray.of_array(matrix.[1])
    freeFunc <- List.Cons( decompVal1.Free, freeFunc )
    let decompVal2 = NativeInterop.PinnedArray.of_array(matrix.[2])
    freeFunc <- List.Cons( decompVal2.Free, freeFunc )
    let decompVal3 = NativeInterop.PinnedArray.of_array(matrix.[3])
    freeFunc <- List.Cons( decompVal3.Free, freeFunc )
    let decompVal = NativeInterop.PinnedArray.of_array([|decompVal0.Ptr;decompVal1.Ptr;decompVal2.Ptr;decompVal3.Ptr|])
    freeFunc <- List.Cons( decompVal.Free, freeFunc )*)
    let decompVal = NativeInterop.PinnedArray.of_array(matrix)
    freeFunc <- List.Cons( decompVal.Free, freeFunc )
    (freeFunc,decompVal)
    
    
/// Decompose the matrix into position, rotation, and scale.
/// This returns a affine parts record
let DecompAffine (matrix : HMatrix) =
    let mutable freeFunc = []
    try
        let hfree,decompVal = HMatrixToNative matrix
        freeFunc <- hfree
        let zerof = 0f
        ///Hopefully the structs are packed.  Using floats, on a 32 bit system they should be.
        let retval = NativeInterop.PinnedArray.of_array([|zerof;zerof;zerof;zerof; //translation
                                                          zerof;zerof;zerof;zerof; //rotation
                                                          zerof;zerof;zerof;zerof; //stretch rotation
                                                          zerof;zerof;zerof;zerof; //stretch factors
                                                          zerof |]) //determinant sign
        let matrixPtr = decompVal.Ptr;
        freeFunc <- List.Cons(retval.Free, hfree)
        decomp_affine(decompVal.Ptr, retval.Ptr)
        let n = retval.NativeArray
        { 
            Translation =       [| n.[0]; n.[1]; n.[2]; n.[3]|]
            Rotation =          [| n.[4]; n.[5]; n.[6]; n.[7]|]
            StretchRotation =   [| n.[8]; n.[9];n.[10];n.[11]|]
            StretchFactors =    [|n.[12];n.[13];n.[14];n.[15]|]
            DeterminantSign =     n.[16]
        }
    finally
        for free in freeFunc do free()
         
         
/// Given a matrix consisting purely of rotations, construct a quaternion
/// representing that matrix.
let QuaternionFromMatrix (matrix:HMatrix) =
    let mutable freeFunc = []
    try
        let hfree,decompVal = HMatrixToNative matrix
        freeFunc <- hfree
        let zerof = 0f
        let retval = NativeInterop.PinnedArray.of_array([|zerof;zerof;zerof;zerof|])
        Qt_FromMatrix(decompVal.Ptr, retval.Ptr)
        let n = retval.NativeArray
        [|n.[0];n.[1];n.[2];n.[3]|]
    finally
        for free in freeFunc do free()
        
    